/**
 * 实体组
 * 
 * 1. 可以监听实体的添加和移除
 * 2. 每个组有对应的match函数，当一个entity被创建、移除或者component发生变化时，会重新刷新
 */

import { Entity } from "./Entity";
import { GenericLinkedList, GenericLinkedListNode } from "./GenericLinkedList";

export class EntityGroup {
    private _groupId:number = 0;
    private _idEntityMap = new Map<number, GenericLinkedListNode<Entity>>();
    private _entityList = new GenericLinkedList<Entity>();
    private _match: (entity: Entity) => boolean;

    constructor(id:number, match: (entity: Entity) => boolean) {
        this._groupId = id;
        this._match = match;
    }

    get groupId() {
        return this._groupId;
    }

    match(entity: Entity) {
        return this._match(entity);
    }

    onEntityAdded(entity: Entity) {
        if (this.match(entity)) {
            this.addEntity(entity);
        }
    }

    onEntityRemove(entity: Entity) {
        let node = this._idEntityMap.get(entity.id);
        if (node) {
            this.removeEntity(node);
        }
    }

    onEntityChanged(entity: Entity) {
        const node = this._idEntityMap.get(entity.id);
        const matches = this.match(entity);
        
        if (node && !matches) {
            this.removeEntity(node);
        } else if (!node && matches) {
            this.addEntity(entity);
        }
    }

    forEach(callback: (entity: Entity) => void) {
        this._entityList.forEach((node) => {
            callback(node.data);
        });
    }

    getCount() {
        return this._entityList.size;
    }

    /**
     * 获取组内所有实体
     * @param out 可选的输出数组，如果提供则使用该数组存储结果
     * @returns 包含所有实体的数组
     */
    getEntities(out: Entity[]): Entity[] {
        out.length = 0; // 清空数组但保留容量
        this._entityList.forEach(node => {
            out.push(node.data);
        });
        return out;
    }

    /**
     * 实现迭代器接口，允许使用 for...of 循环遍历实体
     */
    [Symbol.iterator](): Iterator<Entity> {
        let current = this._entityList.head;
        return {
            next(): IteratorResult<Entity> {
                if (current) {
                    const value = current.data;
                    current = current.next;
                    return { value, done: false };
                }
                return { value: undefined, done: true };
            }
        };
    }

    private addEntity(entity: Entity) {
        let node = this._entityList.addLast(entity);
        this._idEntityMap.set(entity.id, node);
    }

    private removeEntity(node: GenericLinkedListNode<Entity>) {
        this._entityList.remove(node);
        this._idEntityMap.delete(node.data.id);
    }

    clear() {
        this._entityList.clear();
        this._idEntityMap.clear();
    }
}


